using AutoMapper;
using Microsoft.EntityFrameworkCore;
using Terra.Data.Entities;
using Terra.Data.Repository;
using Terra.Data.UnitOfWork;
using Terra.Service.Common.Models;

namespace Terra.Service.Common.Base;

/// <summary>
/// 应用服务基类
/// </summary>
public abstract class AppServiceBase
{
    protected IUnitOfWork UnitOfWork { get; }
    protected IMapper Mapper { get; }

    protected AppServiceBase(
        IUnitOfWork unitOfWork,
        IMapper mapper)
    {
        UnitOfWork = unitOfWork;
        Mapper = mapper;
    }
}

/// <summary>
/// CRUD应用服务基类
/// </summary>
public abstract class CrudAppServiceBase<TEntity, TDto, TKey> : AppServiceBase, ICrudAppService<TDto, TKey>
    where TEntity : class, IEntity<TKey>
    where TDto : class
{
    protected IRepository<TEntity, TKey> Repository => UnitOfWork.GetRepository<TEntity, TKey>();

    protected CrudAppServiceBase(
        IUnitOfWork unitOfWork,
        IMapper mapper) : base(unitOfWork, mapper)
    {
    }

    public virtual async Task<TDto> GetAsync(TKey id)
    {
        var entity = await Repository.GetByIdAsync(id);
        return Mapper.Map<TDto>(entity);
    }

    public virtual async Task<PagedResultDto<TDto>> GetListAsync(PagedRequestDto input)
    {
        var query = Repository.GetQueryable();
        var totalCount = await Repository.CountAsync();

        // 应用分页
        query = query.Skip((input.Page - 1) * input.PageSize).Take(input.PageSize);

        var items = await query.ToListAsync();
        var dtos = Mapper.Map<List<TDto>>(items);

        return new PagedResultDto<TDto>
        {
            Total = totalCount,
            Items = dtos
        };
    }

    public virtual async Task<TDto> CreateAsync(TDto input)
    {
        var entity = Mapper.Map<TEntity>(input);
        entity = await Repository.InsertAsync(entity);
        return Mapper.Map<TDto>(entity);
    }

    public virtual async Task<TDto> UpdateAsync(TKey id, TDto input)
    {
        var entity = await Repository.GetByIdAsync(id);
        Mapper.Map(input, entity);
        entity = await Repository.UpdateAsync(entity);
        return Mapper.Map<TDto>(entity);
    }

    public virtual async Task DeleteAsync(TKey id)
    {
        await Repository.DeleteByIdAsync(id);
    }
}